package com.ruoyi.common.utils.jm;

import sun.security.x509.*;

import java.io.*;
import java.math.BigInteger;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import static com.ruoyi.common.utils.file.FileUtils.byte2Input;


public class CertificateUtil {

    private static int HASHBUFSIZE = 1024*1024;

    public static byte[] ESSGetDigest(byte[] bMsg){
        try
        {
            MessageDigest md = MessageDigest.getInstance("SHA1");
            int iOffset = 0;
            do {
                int len = bMsg.length - iOffset;
                if (len > HASHBUFSIZE)
                    len = HASHBUFSIZE;
                md.update(bMsg, iOffset, len);
                iOffset += len;
            } while (iOffset < bMsg.length);
            return md.digest();
        }catch(GeneralSecurityException e)
        {
            return null;
        }
    }

    /**
     * 解析证书中私钥
     * @param pfx
     * @param pwd
     * @return
     */
    private static PrivateKey GetPrivateKeyByCert(byte[] pfx,String pwd)
    {
        try
        {
            ByteArrayInputStream fis;
            fis = new ByteArrayInputStream(pfx);
            char[] nPassword = pwd.toCharArray();

            KeyStore inputKeyStore = KeyStore.getInstance("PKCS12");

            inputKeyStore.load(fis, nPassword);

            Enumeration<String> enuma = inputKeyStore.aliases();

            String keyAlias = enuma.nextElement();

            Key key = null;
            if (inputKeyStore.isKeyEntry(keyAlias))
                key = inputKeyStore.getKey(keyAlias, nPassword);
            fis.close();
            PrivateKey pk = (PrivateKey)key;
            return pk;
        }catch(IOException | GeneralSecurityException e)
        {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 解析证书的基本信息
     * @param cert
     * @return
     */
    private static X500Name GetIssuerInfo(byte[] cert)
    {

        ByteArrayInputStream byteArrayInputStream;
        try {
            byteArrayInputStream = new ByteArrayInputStream(cert);

            X509CertImpl x509Cert=new X509CertImpl(byteArrayInputStream);

            X509CertInfo x509CertInfo=(X509CertInfo)x509Cert.get(X509CertImpl.NAME+"."+X509CertImpl.INFO);

            return (X500Name) x509CertInfo.get(X509CertInfo.SUBJECT + "." + CertificateIssuerName.DN_NAME);
        } catch (IOException | CertificateException e) {
            e.printStackTrace();
        }
        return null;
    }

    /*
     * 这个按说再是不用管，一时半会用不上
     * 生成自签名证书 ，应将其改造一下。
     * 第一句 x500String= 后面的内容应该改为传入
     * CN 是印章或人员的身份证号码
     * OU 是部门名称，如果是人员，填写其姓名
     * O 是单位名称，如果是人员，填写“ ”
     * L 是单位所在地（市级），如果是人员，填“ ”
     * S 是单位所在地（省级）
     * C 固定是 中国
     * **/
    public static void CreatePfxItSelf() throws NoSuchAlgorithmException, IOException, CertificateException, KeyStoreException, InvalidKeyException, NoSuchProviderException, SignatureException
    {
        String x500String = "CN = 乌江渡发电厂电子签章,OU = 乌江渡发电厂电子签章,O = 乌江渡发电厂,L = 遵义,S = 贵州,C = 中国";
        long lDateLen = 10*365;
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
        kpg.initialize(1024);
        KeyPair keyPair = kpg.generateKeyPair();
        X509CertInfo info = new X509CertInfo();
        Date from = new Date(new Date().getTime()-86400000l);
        long time = from.getTime();
        long agoTime = time-86400000l;
        Date to = new Date(agoTime + lDateLen * 86400000l);
        CertificateValidity interval = new CertificateValidity(from, to);
        BigInteger sn = new BigInteger(64, new SecureRandom());

        X500Name owner = new X500Name(x500String);

        X500Name bIssuer = new X500Name(x500String);
        info.set(X509CertInfo.VALIDITY, interval);
        info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(sn));
        info.set(X509CertInfo.SUBJECT, new CertificateSubjectName(owner));
        info.set(X509CertInfo.ISSUER, new CertificateIssuerName(bIssuer));
        info.set(X509CertInfo.KEY, new CertificateX509Key(keyPair.getPublic()));
        info.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3));
        AlgorithmId algo = new AlgorithmId(AlgorithmId.md5WithRSAEncryption_oid);
        info.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(algo));

        X509CertImpl cert = new X509CertImpl(info);
        cert.sign(keyPair.getPrivate(), "MD5WithRSA");
        KeyStore store = KeyStore.getInstance("PKCS12");
        store.load(null, null);
        store.setKeyEntry("esspfx", keyPair.getPrivate(), "123456".toCharArray(), new Certificate[] { cert });
        FileOutputStream fos =new FileOutputStream("d:/temp/selfPfx.pfx");
        store.store(fos, "123456".toCharArray());
        fos.close();
        return;
    }


    private static String GetDefaultCertOwnerInfo()
    {
        return "CN = ccn,OU = oou,O = oox,L = ool,S = ooS,C = ooC";
    }

    /**
     * 获取私钥别名等信息
     */
    public static String getPrivateKeyInfo(byte[] pfx,String pwd)
    {
        String keyAlias = null;
        try
        {
            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            InputStream byteArrayInputStream = new ByteArrayInputStream(pfx);
            char[] nPassword = pwd.toCharArray();
            keyStore.load(byteArrayInputStream, nPassword);

            Enumeration<String> enumeration = keyStore.aliases();
            if (enumeration.hasMoreElements()) {
                keyAlias = enumeration.nextElement();
            }

            PrivateKey privateKey = (PrivateKey) keyStore.getKey(keyAlias, nPassword);
            Certificate cert = keyStore.getCertificate(keyAlias);
            PublicKey publicKey = cert.getPublicKey();

//            System.out.println("alias=[" + keyAlias + "]");
//            System.out.println("keystore type=" + keyStore.getType());
//            System.out.println("is key entry=" + keyStore.isKeyEntry(keyAlias));
//            System.out.println("cert class = " + cert.getClass().getName());
//            System.out.println("cert = " + cert);
//            System.out.println("public key = " + publicKey);
//            System.out.println("private key = " + privateKey);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return keyAlias;
    }

    /**
     * 解析获得pfx  获得cer证书
     * @param pfx  pfx证书
     * @param pwd 密码
     * @return 返回信息集合
     */
    public static byte[] GetCertFromPfx(byte[] pfx, String pwd) {
        Certificate cert = null;
        try{
            //将临时文件读取
            InputStream inputStream = new ByteArrayInputStream(pfx);
            char[] nPassword = null;
            if ((pwd == null) || pwd.trim().equals("")){
                nPassword = null;
            } else {
                nPassword = pwd.toCharArray();
            }

            KeyStore ks = KeyStore.getInstance("PKCS12");
            ks.load(inputStream, nPassword);
            inputStream.close();
            Enumeration enumas = ks.aliases();

            String keyAlias = null;
            if (enumas.hasMoreElements())// we are readin just one certificate.
            {
                keyAlias = (String)enumas.nextElement();
            }
//            PrivateKey prikey = (PrivateKey) ks.getKey(keyAlias, nPassword);

            cert = ks.getCertificate(keyAlias);
            return cert.getEncoded();
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 解析获得pfx  证书包含的信息
     * @param pfx  pfx证书
     * @param pwd 密码
     * @return 返回信息集合
     */
    public static CertificateInfo GetCertInfoFromPfx(byte[] pfx, String pwd) {
        CertificateInfo certificateInfo = new CertificateInfo();

        try{
            //将临时文件读取
            InputStream inputStream = new ByteArrayInputStream(pfx);
            char[] nPassword = null;
            if ((pwd == null) || pwd.trim().equals("")){
                nPassword = null;
            } else {
                nPassword = pwd.toCharArray();
            }

            KeyStore ks = KeyStore.getInstance("PKCS12");
            ks.load(inputStream, nPassword);
            inputStream.close();
            Enumeration enumas = ks.aliases();

            String keyAlias = null;
            if (enumas.hasMoreElements())// we are readin just one certificate.
            {
                keyAlias = (String)enumas.nextElement();
            }

            // Now once we know the alias, we could get the keys.
//            System.out.println("is key entry=" + ks.isKeyEntry(keyAlias));
            PrivateKey prikey = (PrivateKey) ks.getKey(keyAlias, nPassword);

            Certificate cert = ks.getCertificate(keyAlias);
            //创建X509工厂类
            CertificateFactory cf = CertificateFactory.getInstance("X.509");

            X509Certificate oCert =(X509Certificate)cf.generateCertificate(new ByteArrayInputStream(cert.getEncoded()));

            SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd");
            //获得证书版本
            certificateInfo.setVersion(String.valueOf(oCert.getVersion()));
            //获得证书序列号
            certificateInfo.setsCertNo(oCert.getSerialNumber().toString(16));
            //获得证书有效期
            certificateInfo.setsTimeBegin(dateformat.format(oCert.getNotBefore()));
            //获得证书失效日期
            certificateInfo.setsTimeEnd(dateformat.format(oCert.getNotAfter()));
            //获得证书主体信息
            certificateInfo.setsUserInfo(oCert.getSubjectDN().getName());
            //获得证书颁发者信息
            certificateInfo.setsIssuerInfo(oCert.getIssuerDN().getName());
            //获得证书签名算法名称
            certificateInfo.setsSignAlgName(oCert.getSigAlgName());
            return certificateInfo;
        }catch (Exception e){
            e.printStackTrace();
        }
        return certificateInfo;
    }

    public static CertificateInfo GetCertInfoFromCer(byte[] cerByte) {
        CertificateInfo certificateInfo = new CertificateInfo();
        try {
            InputStream inStream = byte2Input(cerByte);
            //创建X509工厂类
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            //创建证书对象
            X509Certificate oCert = (X509Certificate)cf.generateCertificate(inStream);
            inStream.close();
            SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd");
            //获得证书版本
            certificateInfo.setVersion(String.valueOf(oCert.getVersion()));
            //获得证书序列号
            certificateInfo.setsCertNo(oCert.getSerialNumber().toString(16));
            //获得证书有效期
            certificateInfo.setsTimeBegin(dateformat.format(oCert.getNotBefore()));
            //获得证书失效日期
            certificateInfo.setsTimeEnd(dateformat.format(oCert.getNotAfter()));
            //获得证书主体信息
            certificateInfo.setsUserInfo(oCert.getSubjectDN().getName());
            //获得证书颁发者信息
            certificateInfo.setsIssuerInfo(oCert.getIssuerDN().getName());
            //获得证书签名算法名称
            certificateInfo.setsSignAlgName(oCert.getSigAlgName());
            return certificateInfo;

//            byte[] byt = oCert.getExtensionValue("1.2.86.11.7.9");
//            String strExt = new String(byt);
//            System.out.println("证书扩展域:" + strExt);
//            byt = oCert.getExtensionValue("1.2.86.11.7.1.8");
//            String strExt2 = new String(byt);
//            System.out.println("证书扩展域2:" + strExt2);
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     *
     * @param CN 证书名称
     * @param OU 部门
     * @param O 单位
     * @param L 城市
     * @param S 省
     * @param C 国家
     * @return
     */
    public static String getOwnerString(String CN,String OU,String O,String L,String S,String C){
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("CN="+CN+" ");
        stringBuffer.append("OU="+OU+" ");
        stringBuffer.append("O="+O+" ");
        stringBuffer.append("L="+L+" ");
        stringBuffer.append("S="+S+" ");
        stringBuffer.append("C="+C+" ");
        return stringBuffer.toString();

    }


}
